"""
-*- coding: utf-8 -*-
@Author  : Link
@Time    : 2022/4/29 15:27
@Software: PyCharm
@File    : ui_main.py
@Remark  : 
"""
import gc

import pandas as pd
import psutil
import datetime as dt
from typing import List, Set, Dict, Tuple, Union
import win32com.client as win32

from PySide2.QtCore import QTimer, Slot, Qt, QObject
from PySide2.QtGui import QIcon, QPixmap
from PySide2.QtWidgets import QMainWindow, QApplication, QTextBrowser, QWidget, QVBoxLayout, QMdiArea, \
    QMessageBox

import pyqtgraph as pg
from pyqtgraph.dockarea import *

from chart_core.chart_pyqtgraph.poll import ChartsUi, ChartDockWindow
from chart_core.chart_pyqtgraph.pyqt_chart import PyqtCanvas
from ui_component.ui_common.ui_utils import MdiLoad
from ui_component.ui_main.mdi_data_merge import ContactWidget
from ui_component.ui_main.te.ui_processing import ProcessWidget
from ui_component.ui_main.ui_designer.ui_main import Ui_MainWindow
from ui_component.ui_main.ui_setting import SettingWidget
from ui_component.ui_to_analysis_stdf.ui_stdf import StdfLoadUi
from workspace_core.core_to_analysis_stdf.stdf_variable import GlobalVariable
from workspace_core.li import SummaryCore


class Main_Ui(QMainWindow, Ui_MainWindow):
    mdi_count = 0
    mdi_cache = None  # type: Dict[int, MdiLoad]  # int:mdi_count
    mdi_qt_chart_cache = None  # type: Dict[int, StdfLoadUi]  # int:mdi_count
    focus_id = 0

    def __init__(self, parent=None, license_control=False):
        super(Main_Ui, self).__init__(parent)
        self.setupUi(self)
        self.icon = QIcon()
        self.icon.addPixmap(QPixmap(":/pyqt/source/images/icon_swf.svg"), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(self.icon)
        self.area = DockArea()
        self.setCentralWidget(self.area)
        self.license_control = license_control

        " 单纯用来存放MDI, MDI还是需要放入MERGE功能的 "
        self.mdi_cache = {}

        " 用来存放chart的 "
        self.mdi_qt_chart_cache = {}

        " 需要一个Table来存放测试项目信息 "
        self.setting = SettingWidget(self)
        dock_table = Dock("STDF ANALYSIS", size=(100, 600))
        dock_table.addWidget(self.setting)
        self.setting.group_emit.connect(self.mdi_li_group)

        " 在table下面放一个较小的QTextBrowser,来做一些信息的记录 "
        self.text_browser = QTextBrowser(self)
        dock_text_browser = Dock("TextBrowser", size=(100, 400))
        dock_text_browser.addWidget(self.text_browser)
        self.text_browser.setTextInteractionFlags(Qt.TextEditable)

        self.area.addDock(dock_table, "left")
        self.area.addDock(dock_text_browser, "bottom", dock_table)

        """
        新版本集成在一起
        载入和数据空间是比较考验的, 里面集成的东西过于复杂
        """
        self.load_widget_mdi = QMdiArea(self)
        self.load_widget_mdi.scrollContentsBy(2000, 2000)
        self.load_widget_mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.load_widget_mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        dock_stdf_windows = Dock("Load STDF Mdi Widget", size=(400, 100))
        self.area.addDock(dock_stdf_windows, "right")
        dock_stdf_windows.addWidget(self.load_widget_mdi)

        self.cpu_percent = []
        self.rom_percent = []
        self.monitor_widget = QWidget(self)
        self.monitor_widget_verticalLayout = QVBoxLayout(self.monitor_widget)
        self.cpu_percent_pg, _ = PyqtCanvas.set_graph_ui(self.monitor_widget_verticalLayout, "CPU占用监控")
        self.rom_percent_pg, _ = PyqtCanvas.set_graph_ui(self.monitor_widget_verticalLayout, "内存占用监控")

        dock_monitor = Dock("System Status", size=(100, 300))
        dock_monitor.addWidget(self.monitor_widget)

        self.area.addDock(dock_monitor, "bottom", dock_text_browser)
        self.area.moveDock(dock_text_browser, 'above', dock_monitor)

        self.mdi_contact_dialog = ContactWidget(None, self.icon)
        self.mdi_contact_dialog.messageSignal.connect(self.mdi_space_message_emit)
        self.mdi_contact_dialog.dataSignal.connect(self.mdi_space_data_contact)

        self.process_widget = ProcessWidget(None, self.icon)
        self.process_widget.hide()

        self.recode_timer = QTimer(self)
        self.recode_timer.timeout.connect(self.recode_system_status)
        self.recode_timer.start(3000)
        self.now_space_timer = QTimer(self)
        self.now_space_timer.timeout.connect(self.scan_now_space)
        self.now_space_timer.start(300)

    def recode_system_status(self):
        """
        系统状态监控
        :return:
        """
        if len(self.rom_percent) > 320:
            self.rom_percent.pop(0)
            self.cpu_percent.pop(0)
        rom_percent = psutil.virtual_memory()[2]
        cpu_percent = psutil.cpu_percent()
        self.rom_percent.append(rom_percent)
        self.cpu_percent.append(cpu_percent)
        rom_pen = '#FFA500' if rom_percent > 85 else 'g'
        cpu_pen = '#FFA500' if cpu_percent > 85 else 'g'
        rom_pen = 'r' if rom_percent > 95 else rom_pen
        cpu_pen = 'r' if cpu_percent > 95 else cpu_pen
        self.cpu_percent_pg.plot(self.cpu_percent, pen=cpu_pen, clear=True)
        self.rom_percent_pg.plot(self.rom_percent, pen=rom_pen, clear=True)

    def scan_now_space(self):
        now = self.load_widget_mdi.activeSubWindow()
        if now is not None:
            """
            做任何处理都需要先判断 focus_id 是否在cache中
            """
            self.focus_id = now.widget().space_nm

    def check_focus_id_with_return(self) -> Union[None, QObject]:
        if self.focus_id in self.mdi_cache:
            mdi_load = self.mdi_cache[self.focus_id]  # type:MdiLoad
            return mdi_load.mdi

    @Slot()
    def on_action_add_stdf_module_triggered(self):
        """
        加载模块, 到MDI空间中
        :return:
        """
        self.mdi_count += 1
        home_load_mdi = StdfLoadUi(self, space_nm=self.mdi_count)
        home_load_mdi.closeSignal.connect(self.mdi_space_delete)
        self.mdi_cache[self.mdi_count] = MdiLoad(self.mdi_count, home_load_mdi,
                                                 "STDF数据载入空间: {}".format(self.mdi_count))
        self.load_widget_mdi.addSubWindow(home_load_mdi)
        home_load_mdi.show()

    @Slot()
    def on_action_path_select_triggered(self):
        """
        加载模块, 到MDI空间中, 这个是选取文件夹
        """
        self.mdi_count += 1
        home_load_mdi = StdfLoadUi(self, space_nm=self.mdi_count, path_select=True)
        home_load_mdi.closeSignal.connect(self.mdi_space_delete)
        self.mdi_cache[self.mdi_count] = MdiLoad(self.mdi_count, home_load_mdi,
                                                 "STDF数据载入空间: {}".format(self.mdi_count))
        self.load_widget_mdi.addSubWindow(home_load_mdi)
        home_load_mdi.show()

    @Slot()
    def on_action_pyside2_triggered(self):
        QApplication.aboutQt()

    @Slot()
    def on_action_email_triggered(self):
        if self.message_show(
                'mail.To = "lihuan.hello@qq.com"\r\nmail.Cc = "865789047@qq.com"\r\n点击确认使用outlook反馈问题'):
            QTimer.singleShot(0, self.send_email)

    @staticmethod
    def send_email():
        outlook = win32.Dispatch('outlook.application')
        mail = outlook.CreateItem(0)
        mail.To = "lihuan.hello@qq.com"
        mail.Cc = "lihuan.hello@qq.com"
        mail.Subject = "STDF数据解析BUG反馈"
        mail.Display(False)

    @Slot()
    def on_action_cascade_triggered(self):
        self.load_widget_mdi.cascadeSubWindows()

    @Slot()
    def mdi_li_group(self) -> QWidget:
        mdi = self.check_focus_id_with_return()  # type:StdfLoadUi
        if mdi is None:
            return self.mdi_space_message_emit("未选定组件@")
        if not mdi.li.set_front_df_group(self.setting.get_group_params(), self.setting.get_da_group_params()):
            return self.mdi_space_message_emit("数据未处理准备完成!@")
        return mdi

    def get_df_with_df_limit(self):
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        text_column = mdi.get_text_column()
        if text_column is None:
            self.message_show("未选取测试项目无法进行图形生成@")
            return
        df_column = GlobalVariable.JMP_SCRIPT_HEAD + text_column
        jmp_df = mdi.li.dt[df_column]
        jmp_limit = [mdi.li.front_limit_dict[key] for key in text_column]
        jmp_cpk = [mdi.li.cpk_dict[key] for key in text_column]
        return jmp_df, jmp_limit, jmp_cpk

    # TODO: 对于QT进行绘图, 应当尽可能的一个MDI对应一个window, 而这个window可以在其中放置多个MDI
    @Slot()
    def on_action_qt_distribution_triggered(self):
        """ 使用PYQT来拉出横向柱状分布图 """
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        if GlobalVariable.OPEN_SAVE_PKL:
            mdi.li.save_to_obj("qt_distribution")
        chart_ui = self.mdi_qt_chart_cache.get(mdi.space_nm, None)
        if chart_ui is None:
            chart_ui = ChartDockWindow(self, icon=self.icon, space_nm=mdi.space_nm)  # type:ChartDockWindow
            self.mdi_qt_chart_cache[mdi.space_nm] = chart_ui
        text_column = mdi.get_text_column()
        chart_ui.qt_distribution.clear()
        chart_ui.dock_qt_distribution.show()
        chart_ui.qt_distribution.set_data(mdi.li, text_column, self.setting.kwargs, 'trans_bar')
        chart_ui.show()

    @Slot()
    def on_action_qt_comparing_triggered(self):
        """ 使用PYQT来拉出比较密度图 """
        if getattr(self, "qt_compare", None) is None:
            self.qt_compare = ChartsUi()
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        text_column = mdi.get_text_column()
        self.qt_compare.hide()
        self.qt_compare.clear()
        self.qt_compare.set_data(mdi.li, text_column, self.setting.kwargs, 'comparing')
        self.qt_compare.show()

    @Slot()
    def on_action_qt_scatter_triggered(self):
        """ 使用PYQT来拉出线性散点图 """
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        if GlobalVariable.OPEN_SAVE_PKL:
            mdi.li.save_to_obj("qt_scatter")
        chart_ui = self.mdi_qt_chart_cache.get(mdi.space_nm, None)
        if chart_ui is None:
            chart_ui = ChartDockWindow(self, icon=self.icon, space_nm=mdi.space_nm)  # type:ChartDockWindow
            self.mdi_qt_chart_cache[mdi.space_nm] = chart_ui
        text_column = mdi.get_text_column()
        chart_ui.qt_scatter.clear()
        chart_ui.dock_qt_scatter.show()
        chart_ui.qt_scatter.set_data(mdi.li, text_column, self.setting.kwargs, 'scatter')
        chart_ui.show()

    @Slot()
    def on_action_qt_mapping_triggered(self):
        """ 使用PYQT来拉出Mapping图 """
        pass

    @Slot()
    def on_action_qt_visual_map_triggered(self):
        """ 使用PYQT来拉出Visual Map图 """
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        if GlobalVariable.OPEN_SAVE_PKL:
            mdi.li.save_to_obj("qt_visual_map")
        chart_ui = self.mdi_qt_chart_cache.get(mdi.space_nm, None)
        if chart_ui is None:
            chart_ui = ChartDockWindow(self, icon=self.icon, space_nm=mdi.space_nm)  # type:ChartDockWindow
            self.mdi_qt_chart_cache[mdi.space_nm] = chart_ui
        text_column = mdi.get_text_column()
        chart_ui.qt_visual_map.clear()
        chart_ui.qt_visual_map.set_data(mdi.li, text_column, self.setting.kwargs, 'visual_map')
        chart_ui.dock_qt_visual_map.show()
        chart_ui.show()

    @Slot()
    def on_action_processing_report_triggered(self):
        """
        制程能力报告
        :return:
        """
        mdi = self.mdi_li_group()  # type:StdfLoadUi
        if mdi is None:
            return
        self.process_widget.set_data(mdi.li)
        self.process_widget.set_front_df_process()
        self.process_widget.show()

    @Slot()
    def on_action_contact_triggered(self):
        """
        用于数据contact, 将两份或是多份数据contact在一起来组合分析, 生成一个新的界面, 而且界面可以简单一些, 加载的功能项目少一点
        数据 contact summary 和 li
        :return:
        TODO:
            1. 要找到当前所有的mid, 在mdi_cache中
            2. mdi_cache的键是mdi_count(small int),
            3. 获取到值(MdiLoad类型)的name
            4. 最终合成一份没有tree_load的widget(hide)
        """
        if not self.mdi_cache:
            return self.mdi_space_message_emit("无法进行Merge, 无任何可Merge窗口")
        self.mdi_contact_dialog.insert(self.mdi_cache)
        self.mdi_contact_dialog.show()

    @Slot(SummaryCore)
    def mdi_space_data_contact(self, data: SummaryCore):
        """ 根据弹出的选择界面, 用来将多个mdi的数据merge在一起 """
        self.mdi_count += 1
        merge_mdi = StdfLoadUi(self, space_nm=self.mdi_count, select=False)
        merge_mdi.dock_file_load.hide()
        self.mdi_cache[self.mdi_count] = MdiLoad(self.mdi_count, merge_mdi,
                                                 "STDF数据载入空间: {}".format(self.mdi_count))
        """ 设置数据 """
        merge_mdi.merge_data_emit(data)
        self.load_widget_mdi.addSubWindow(merge_mdi)
        merge_mdi.show()

    @Slot(str)
    def mdi_space_message_emit(self, message: str):
        """
        append message
        :param message:
        :return:
        """
        self.statusbar.showMessage("==={}==={}===".format(dt.datetime.now().strftime("%H:%M:%S"), message))

    def delete_mdi(self, count_id):
        mdi = self.mdi_cache.get(count_id, None)
        if mdi is not None:
            del self.mdi_cache[count_id]

    def delete_mdi_chart(self, count_id):
        qt_chart = self.mdi_qt_chart_cache.get(count_id, None)
        if isinstance(qt_chart, ChartDockWindow):
            qt_chart.close()
            qt_chart.clear()
            del self.mdi_qt_chart_cache[count_id]

    @Slot(int)
    def mdi_space_delete(self, count_id: int):
        QTimer.singleShot(100, lambda: self.delete_mdi(count_id))
        QTimer.singleShot(100, lambda: self.delete_mdi_chart(count_id))

    def message_show(self, text: str) -> bool:
        res = QMessageBox.question(self, '待确认', text,
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.Yes)
        if res == QMessageBox.Yes:
            return True
        else:
            return False

    def save_df_to_csv(self, data_object: pd.DataFrame, file_path):
        if data_object is None:
            return self.mdi_space_message_emit('未查询 空数据无法保存!!! ')
        if any(data_object):
            data_object.to_csv(file_path, encoding='utf_8_sig', index=False)
            self.mdi_space_message_emit(f'数据保存成功,路径在:>>>{file_path},开始执行JMP脚本')
            return file_path
        else:
            self.mdi_space_message_emit('未查询 空数据无法保存!!! ')
            return None


class Application(QApplication):
    def __init__(self, argv):
        QApplication.__init__(self, argv)
        # QApplication.setStyle('fusion')
